home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Belgian Amiga Club - ADF Collection
/
BS1 part 68.7z
/
BS1 part 68
/
EGS Retina For TVPaint Pro v2.0.1 AGA (1993)(-)(DE)(Diskette 2 of 2).7z
/
EGS Retina For TVPaint Pro v2.0.1 AGA (1993)(-)(DE)(Diskette 2 of 2).adf
/
Entwickler.lha
/
Entwickler
/
Entwickler.dok
< prev
next >
Wrap
Text File
|
1993-10-12
|
40KB
|
1,025 lines
*********************************************************
* *
* Dokumentation *
* *
* für Entwickler *
* *
* 12.10.1993 *
* *
* Cinema 4D *
* *
*********************************************************
Das Koordinatensystem von Cinema4D ist so definiert, daß X- und Y- Achse in
der Monitorebene liegen und die Z-Achse dazu senkrecht nach hinten zeigt.
Cinema4D verwendet bei Dateien zur Speicherung von Koordinaten
ausschließlich FFP-Variablen, wodurch die Kompatibilität des Dateiformats
zur 68881-er Version, die intern mit LONGREAL-Variablen arbeitet,
gewährleistet ist. Cinema4D-Erweiterungen dagegen müssen wie das
Hauptprogramm in zwei Versionen vorliegen: eine 68000-er und eine 68881-er
Version.
Bei der Erstellung von eigenen Programmen ist umbedingt darauf zu achten,
daß alle Werte die Spezifikationen, die in dieser Dokumentation angegeben
sind, erfüllen. Ist dies nicht der Fall, kann es zu unerwarteten Effekten
oder sogar Systemabstürzen führen.
Sämtliche Deklarationen sind in Modula-2 aufgeführt; die Umsetzung dürfte
aber C-Programmierern keine Schwierigkeit bereiten.
CONST
MINSIZE = 0.001;
MAXREAL = 1000000.0;
MAXELEMENTS = 65520;
MAXPOLYPNTS = 2500;
TYPE
VEKTOR = RECORD
x,y,z : FFP;
END;
Der Datentyp 'VEKTOR' wird als Vektor, Punkt und Farbe eingesetzt.
Wird er als Farbe verwendet, entspricht der x-Komponente der Rotanteil,
der y-Komponente der Grünanteil und der z-Komponente der Blauanteil. Jede
Komponente muß größer oder gleich null und kleiner gleich eins sein.
Wird 'VEKTOR' als Punkt verwendet, so sollten die einzelnen Komponenten
zwischen -MAXREAL und +MAXREAL liegen. Dies gilt nicht nur für Punkte,
sondern auch für Abstände, Radien usw..
Darst = (keine,quader,voll);
Darstellung von Körpern und Polygonen :
keine : keine Darstellung
quader : Darstellung durch einenumhüllende Quader
voll : Volldarstellung
MATRIX = ARRAY [0..3],[0..3] OF FFP;
Matrix zur Speicherung einer dreidimensionalen Transformation. Im Fall
eines Körpers muß die Matrix auf folgende Werte gesetzt werden:
m[0,0]:=1.0; m[0,1]:=0.0; m[0,2]:=0.0; m[0,3]:=0.0;
m[1,0]:=mp.x; m[1,1]:=v1.x; m[1,2]:=v2.x; m[1,3]:=v3.x;
m[2,0]:=mp.y; m[2,1]:=v1.y; m[2,2]:=v2.y; m[2,3]:=v3.y;
m[3,0]:=mp.z; m[3,1]:=v1.z; m[3,2]:=v2.z; m[3,3]:=v3.z;
Die Matrix dient dem Programm dazu, den Quader, der beim Verschieben,
Skalieren und Drehen auf dem Bildschirm erscheint, zu berechnen.
5------------6 v2
/| /| | v3
1-+----------2 | | /
| | | | |/
| | 9 | | +----- v1
| | | |
| 7----------+-8
|/ |/
3------------4
Die Punkte (1)-(9) ergeben sich folgendermaßend :
(1) : mp-v1+v2-v3
(2) : mp+v1+v2-v3
(3) : mp-v1-v2-v3
(4) : mp+v1-v2-v3
(5) : mp-v1+v2+v3
(6) : mp+v1+v2+v3
(7) : mp-v1-v2+v3
(8) : mp+v1-v2+v3
(9) : mp
Bei einem neu erzeugten Körper ist die Körpermatrix meistens noch
ungedreht, das heißt parallel zum Weltkoordinatensystem.
Wird ein Körper gedreht, muß auch die Matrix mitgedreht werden. Wird es
Verschoben, muß die Matrix verschoben werden. Ebenso muß bei einer
Skalierung oder Spiegelung die Matrix geändert werden. Die Vektoren
'v1', 'v2' und 'v3' müssen immer genau so lang sein, daß alle Punkte des
Körpers innerhalb der Begrenzungsbox liegen. Sie dürfen minimal eine
Länge von 'MINSIZE' (oben definiert) haben, auch wenn der Körper kleiner
ist. 'mp' ist der Mittelpunkt des gedrehten Systems, nicht der
Mittelpunkt in Weltkoordinaten.
STRING = ARRAY [0..15] OF CHAR;
Zeichenkette für Körper-, Lichtquellen- und Polygonnamen. Die
Zeichenkette muß mindestens ein Zeichen enthalten.
STRING64 = ARRAY [0..63] OF CHAR;
Zeichenkette für Texturnamen. Die Zeichenkette muß mindestens
ein Zeichen enthalten.
LichtFlags = (schattenwurf,spot,abnahme,parallel);
LichtFlagSet = SET OF LichtFlags;
Flags einer Lichtquelle. Damit kann festgelegt werden, ob die Lichtquelle
Schatten werfen soll, ob sie eine Spotlichtquelle ist, ob ihre
Lichtintensität bei zunehmender Entfernung abnimmt, und ob sie parallele
Lichtstrahlen aussendet.
LichtPtr = POINTER TO LICHT;
LICHT = RECORD
name : STRING;
flags : LichtFlagSet;
p,f,p2 : VEKTOR;
abn,w,hell : FFP;
nextlicht : LichtPtr;
END;
'name' gibt den Lichtquellennamen an. 'p' ist die Position, an der sich
die Lichtquelle befindet. 'f' ist die Farbe der Lichtquelle. 'p2' gibt
die Zielposition der Lichtquelle an (für Spot- und Parallellicht). 'P2'
muß umbedingt von 'p' verschieden sein, selbst wenn 'p2' nicht benutzt
wird. 'abn' ist ein positiver Wert größer null. Er gibt an, wie weit die
Lichtquelle strahlt.Dazwischen wird linear die Abnahme berechnet (d.h.
Entfernung 0 = 100%, 'abn'/2 = 50%, 'abn' = 0%). Die Helligkeit ist ein
Wert größer Null und kleiner gleich 10. Er gibt die Helligkeit der
Lichtquelle an. Der Wert 1 entspricht 100%. 'w' hat je nach
Lichtquellenart verschiedene Bedeutungen : handelt es sich um eine
Spot-/Parallellichtquelle, dann steht in 'w' ein Wert größer null, der
den Radius des Lichtzylinders angibt. Handelt es sich dagegen um eine
Spotlichtquelle ohne Parallellicht, dann gibt 'w' den gesamten
Abstrahlwinkel des Lichtkegels an. 'w' muß dann größer null und kleiner
360 sein. 'nextlicht' ist ein Zeiger auf die nächste Lichtquelle.
KAMERA = RECORD
p1,p2 : VEKTOR;
f,w,zoom : FFP;
v1,v2,v3 : VEKTOR;
END;
'p1' ist die Position der Kamera, 'p2' der Zielpunkt. Position und
Zielpunkt müssen voneinander verschieden sein. 'f'/2.8 gibt die
Brennweite der Kamera an. 'f' muß größer gleich 2.8 sein. 'w' legt den
Neigungswinkel der Kamera fest. 'zoom' ist der Zoomfaktor, der größer
gleich 0.001 und kleiner gleich 1000.0 sein muß. 'v1', 'v2' und 'v3'
geben die Kameravektoren an. Die Initialisierung übernimmt Cinema4D.
TexFlags = (Farbe,Trans,Relief,Spieg);
TexFlagSet = SET OF TexFlags;
Die 'TexFlags' geben an für welche der Texturarten eine Bedingung
erfüllt ist.
MaterialPtr = POINTER TO MATERIAL;
MATERIAL = RECORD
name : ARRAY [0..23] OF CHAR;
f,t,v : VEKTOR;
h,brech,winkel,
abn,leucht : FLOAT;
ftex,ttex,stex,rtex : STRING64;
selbst,nebel : BOOLEAN;
tex,verlauf,eckig : TexFlagSet;
nofresnel : BOOLEAN;
reserved : ARRAY [0..15] OF CHAR;
nextmat : MaterialPtr;
END;
In 'name' steht der Materialname. Die Zeichenkette muß mindestens ein
Zeichen enthalten. 'f','t' und 'v' sind Farbwerte und geben
Materialfarbe, Transparenz und Spiegelung an. 'h' ist die Oberflächengüte
und muß größer gleich 0 und kleiner gleich 100 sein. 0 bedeutet kein
Glanzlicht. Werte größer Null erzeugen ein Glanzlicht. Je größer der
Wert, desto kleiner das Glanzlicht (Umgekehrt zur Benutzereingabe!). In
'brech' steht der Brechungsindex des Materials. Er muß größer gleich 0.25
und kleiner gleich 4 sein. 'winkel' ist der Winkel für Relieftexturen.
Er muß größer null und kleiner gleich 100 sein.In 'abn' steht die Abnahme
von Lichtstrahlen bei Nebel. 'abn' muß größer Null sein. Es folgen in
'ftex', 'ttex', 'stex' und 'rtex' die Pfade für Farb-, Transparenz-,
Spiegel- und Relieftexturen. 'selbst' gibt an, ob das Material
selbstleuchtend ist. Mit 'leucht' legen Sie den selbstleuchtenden Anteil
fest. In 'tex' steht, welche Texturen gerade angeschaltet
sind. Ist das entsprechende Flag in 'verlauf' gesetzt, dann handelt es
sich um eine Verlaufstextur. Ist das Flag in 'eckig' gesetzt, wird ein
Misch-Verlauf, ansonsten ein Punkt-Verlauf berechnet. 'nebel' gibt an,
ob das Material als Nebel verwendet werden soll. 'nofresnel' gibt an,
ob die Brechung bzw. das Transparenz- und Spieglungsverhalten physikalisch
korrekt erfolgen soll (true=nein, false=ja, für genauere Angaben siehe
Handbuch). 'nextmat' ist der Zeiger auf das nächste Material.
PROJEKTION = (Kug,Zylinder,Flaeche);
Textur-Projektionsart : Kugel/Zylinder/Fläche
TexInfoPtr = POINTER TO TEXINFO;
TEXINFO = RECORD
mp,v1,v2,v3 : VEKTOR;
ox,oy,lenx,leny : FFP;
mehrfach : BOOLEAN;
projekt : PROJEKTION;
END;
'TEXINFO' ist die Textur-Information eines Körpers. 'mp', 'v1', 'v2' und
'v3' sind diesmal nicht in einer Matrix gespeichert, sondern als
Vektoren. Sie haben die gleiche Bedeutung wie oben besprochen, diesmal
aber nicht für die Körper-Box sondern für die Textur-Box. 'ox' und 'oy'
stellen den Offset des Texturbildes dar (siehe Offset.iff). 'lenx' und
'leny' geben die Größe des Texturbildes an und müssen größer gleich -1
und kleiner gleich 1 sein. Sie dürfen nicht auf 0 gesetzt werden, es sei
denn, es handelt sich um ein Pseudo-Körper. Mit 'mehrfach' wird festgelegt,
ob es sich um eine Mehrfachtextur handelt. Schließlich gibt 'projekt' noch
die Projektion an. Bei der Zylinder- und Kugelprojektion darf 'ox' nicht
beliebig gewählt werden. Dies gilt auch für 'oy' bei Kugelprojektion.
Ist 'lenx' positiv so muß 'ox' minimal auf 0 und maximal auf 1-'lenx'
gesetzt werden. Ansonsten darf 'ox' minimal 1+lenx und maximal 1
betragen. Mit 'oy' verhält es sich dementsprechend.
KOERPERTYP = (Kugel,Flaechen,Pseudo);
Art des Körpers: Kugel, Körper aus Flächen oder Verzeichnis
KorperPtr = POINTER TO KOERPER;
KOERPER = RECORD
CASE typ:KOERPERTYP OF
| Flaechen : panz,danz,vanz,kanz : LONGINT;
padr,dadr,vadr,kadr : ADDRESS;
| Pseudo : adr : KoerperPtr;
reserved1 : ARRAY [0..27] OF CHAR;
| Kugel : reserved2 : ARRAY [0..31] OF CHAR;
END;
mp,r : VEKTOR;
matrix : MATRIX;
name : STRING;
info : TEXINFO;
phong : BOOLEAN;
darst : Darst;
mat : MaterialPtr;
reserved : ARRAY [0..11] OF CHAR;
next : KoerperPtr;
END;
'typ' gibt an, um was für ein Körper es sicht handelt. Ist es ein aus
Flächen aufgebauter Körper, dann folgen in 'panz' die Anzahl der Punkte,
in 'danz' die Anzahl der Dreiecke, in 'vanz' die Anzahl der Vierecke und
in 'kanz' die Anzahl der Kanten. Anschließend sind die entsprechenden
Adressen vermerkt.'panz' und 'kanz' und entweder 'danz' oder 'vanz' oder
beide müssen größer null sein. Entsprechend müssen die Adressen ungleich
NIL sein. Ab 'padr' folgen 'panz' Punkte des Körpers, als Vektoren
gespeichert (d.h. 12 Bytes pro Punkt). Dreiecke bestehen aus drei
CARDINAL-Nummern. Jede Nummer gibt dabei einen Punkt an (beginnend mit
null). Ebenso sind Vierecke gespeichert, allerdings durch vier
CARDINAL-Nummern. Kanten werden durch zwei CARDINAL-Nummern gespeichert.
Die Anzahl von Punkten, Kanten, Dreiecken und Vierecken ist auf
'MAXELEMENTS' begrenzt. Es ist umbedingt wichtig, daß die Kanten korrekt
angelegt werden, daß heißt jede Kante darf nur einmal vorkommen.
Handelt es sich um ein Körperverzeichnis ('Pseudo'), dann steht in 'adr'
ein Zeiger auf den ersten untergeordneten Körper. Der nächste Körper auf
gleicher Ebene dagegen ist in 'next' vermerkt. Es ist zwingend
erforderlich, Körper korrekt zu verknüpfen, da sich sonst Cinema4D in
einer Endlosschleife aufhängt.
In 'mp' und 'r' stehen Mittelpunkt und Radius des Körpers im
Weltkoordinatensystem. Es handelt sich dabei um vollkommen andere Werte
als die in 'matrix' gespeicherten, da diese sich auf das
Körperkoordinatensystem beziehen. Jede Komponente von r muß größer gleich
null sein. In 'name' steht der Körpername, in 'info' die Textur-
Information. 'phong' gibt an, ob der Körper mit Phong-Shading berechnet
werden soll. Dazu müssen aber alle Dreiecke und Vierecke einheitlich
ausgerichtet sein. In 'darst' ist vermerkt, wie der Körper im Editor
dargestellt wird. 'mat' ist ein Zeiger auf das dem Körper zugeordneten
Material. Wenn 'mat' auf NIL steht, dann wird ein Standardmaterial
verwendet.
Für ein Körperverzeichnis muß nur ein Teil seiner Matrix initialisiert
sein. Die drei Basisvektoren geben nur die Richtungen angeben, ihre
Längen dagegen sind unwichtig. Der Mittelpunkt der Matrix muß nicht
initialisiert werden und sollte auf den Weltkoordinatenursprung (0/0/0)
gesetzt werden.
SplineArt = (Linear,Kubisch,Akima,BSpline);
PolygonPtr = POINTER TO POLYGON;
POLYGON = RECORD
name : STRING;
panz : LONGINT;
splineart : SplineArt;
geschlossen : BOOLEAN;
darst : Darst;
mp,r : VEKTOR;
padr : ADDRESS;
koadr : ADDRESS;
next : PolygonPtr;
END;
In 'name' steht der Name des Polygons. 'panz' muß größer 1 sein und darf
maximal 'MAXPOLYPNTS' betragen. In 'splineart' steht die Art des
Polygons. geschlossen gibt an, ob das Polygon geschlossen ist, oder
nicht. 'darst' gibt an, wie das Polygon im Editor dargestellt wird.
'mp' und 'r' geben Mittelpunkt und Radius des Polygons in Weltkoordinaten
an, wobei jede Komponente des Radius größer gleich null sein muß. 'padr'
ist ein Zeiger auf die Punkte des Polygons. Bei nichtlinearen Polygonen
sind zusätzlich noch in koadr Koeffizienten abgespeichert, die das
Arbeiten im Editor beschleunigen. Die Berechnung ist sehr aufwendig.
Verändern Sie deshalb bitte nur lineare Polygone.
'next' ist ein Zeiger auf das nächste Polygon.
HintergrundFlags = (nebel,tex,verlauf,eckig);
HintergrundFlagSet = SET OF HintergrundFlags;
HINTERGRUND = RECORD
f,t : VEKTOR;
abn : FFP;
flags : HintergrundFlagSet;
reserved : BOOLEAN;
iffname : STRING64;
reserved2 : ARRAY [0..3] OF CHAR;
END;
Hintergrundsdefinition einer Szene. In 'f' und 't' stehen Farbe und
Transparenz des Hintergrunds (Transparenz des Nebels). In 'iffname' steht
der Name der Textur. Die Bedeutung der restlichen Werte kann bei
'MATERIAL' nachgelesen werden.
BODEN = RECORD
ex : BOOLEAN;
mat : MaterialPtr;
info : TEXINFO;
END;
In 'ex' ist vermerkt, ob der Boden angeschaltet ist. 'mat' ist ein Zeiger
auf das verwendete Material und 'info' ist die Textur-Information.
UMGEBUNG = RECORD
boden,himmel : BODEN;
xyzkamera : KAMERA;
hintergrund : HINTERGRUND;
END;
Definition der Szenenumgebung : Boden, Himmel, Kamera und Hintergrund
WEITER = SET OF (next,reserved1,reserved2,pseudoempty);
Alle diese Definitionen geben an, wie Körper, Polygone, Lichtquellen usw.
im Hauptspeicher angegeben sind. Wer Erweiterungen für Cinema4D
programmiert, kann damit direkt darauf zugreifen.
************************************************************************************************
Das Dateiformat von Cinema4D ist ein IFF-Format. Die FORM-ID heißt 'FRAY'.
Es gibt mehrere Chunks:
'POLY' : Dieser Chunk enthält alle Polygone. Wenn er vorhanden ist,
enthält er mindestens ein Polygon. Dieser Chunk sollte als Erster gespeichert werden,
da andere Chunks auf ihn eventuell Referenzen haben.
'FRE1' : Dieser Chunk enthält sämtliche Requester-Einstellungen des Editors. Er sollte
vor den restlichen Chunks abgespeichert werden.
'MAT1' : Dieser Chunk enthält alle Materialien. Er muß -falls vorhanden-
vor dem 'OBJ1' und 'UMG1'-Chunk stehen, da diese Chunks
Materialnummern enthalten und sich auf den 'MAT1'-Chunk beziehen.
Wenn der 'MAT1'-Chunk vorhanden ist, dann enthält er mindestens
ein Material.
'UMG1' : Dieser Chunk enthält die Umgebungsdaten einer Szene.
'OBJ1' : Dieser Chunk enthält alle Körper. Wenn er vorhanden ist, enthält
er mindestens einen Körper.
'LAM1' : Dieser Chunk enthält alle Lichtquellen. Wenn er vorhanden ist,
enthält er mindestens eine Lichtquelle.
'ANIM' : Dieser Chunk enthält sämtliche Animationsdaten.
'CPPL' : Dieser Chunk enthält sämtliche Polygonlisten der
Polygonfunktionen. Er kommt vor, wenn es auch einen 'FRE1'-Chunk
gibt.
'MAT1'-Chunk
************
REPEAT
Lese Material.name bis Material.nebel (342 Bytes)
Lese Weiter (1 Byte)
UNTIL NOT(next IN Weiter);
Falls Chunklänge ungerade : ein Dummybyte lesen
Auszug aus einer Beispielsdatei (Material mit dem Namen 'Rotes Plastik',
einer Farbtextur und einer Relieftextur)
4D415431 MAT1
00000157 4D61726D 6F720064 00000000 ...WMarmor.d....
00000000 00000000 00000000 80000041 ...............A
00000000 80000040 00000000 00000000 .......@........
00000000 99999A3F 99999A3F 99999A3F .......?...?...?
A1FFFF47 80000041 A0000045 C8000047 ¡..G...A ..EÈ..G
80000041 54657874 7572656E 2F4D6172 ...ATexturen/Mar
6D6F7200 00000000 00000000 00000000 mor.............
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 54657874 7572656E 2F4D6172 ....Texturen/Mar
6D6F722D 48F66865 6E766572 6C617566 mor-Höhenverlauf
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 0000050F 00000000 ............
'LAM1'-Chunk
************
Wiederhole
Lese Licht.name bis Licht.hell (66 Bytes)
Lese Weiter (1 Byte)
Bis NOT(next IN Weiter);
Falls Chunklänge ungerade : ein Dummybyte lesen
Auszug aus einer Beispielsdatei (Spot-Lichtquelle mit dem Namen 'Licht')
4C41 4D310000 LAM1..
00434C69 63687400 00000000 00000000 .CLicht.........
00000200 A00000C9 F0000048 00000000 .... ..Éð..H....
80000041 80000041 80000041 00000000 ...A...A...A....
00000000 C8000047 C8000047 F0000045 ....È..GÈ..Gð..E
80000041 0200 ...A..
'POLY'-Chunk
************
Wiederhole
Lese Polygon.name bis Polygon.darst (23 Bytes)
Lese Polygon.mp bis Polygon.r (24 Bytes)
Lese Polygonpunkte (12*Polygon.panz Bytes)
Falls Polygon.splineart#Linear dann
Lese Koeffizienten (BSpline: 4 Bytes,
Kubisch: 48*(Polygon.panz+1) Bytes,
Akima: 48*(Polygon.panz+5) Bytes)
Lese Weiter (1 Byte)
Bis NOT(next IN Weiter);
Falls Chunklänge ungerade : ein Dummybyte lesen
Auszug aus einer Beispielsdatei (Lineares Polygon mit dem Namen 'Polygon')
504F 4C590000 0060506F POLY...`Po
6C79676F 6E000000 00000000 00000000 lygon...........
00040000 02C80000 C6F00000 44000000 .....È..Æð..D...
00C80000 49848000 49000000 00E10000 .È..I...I....á..
C9D20000 48000000 00FA0000 C8FA0000 ÉÒ..H....ú..Èú..
C8000000 00D20000 488C0000 C8000000 È....Ò..H...È...
00AF0000 498C0000 49000000 0002 .¯..I...I.....
'OBJ1'-Chunk
************
Da Körper Unterkörper haben können, ist der 'OBJ1'-Chunk rekursiv
verschachtelt.
Prozedur LadeKörper
Wiederhole
Lese Koerper.art (1 Byte)
Lese Koerper.mp bis Koerper.darst (172 Bytes)
Lese Materialnummer (2 Bytes) Die Materialnummer muß beim Laden in
einen MaterialPtr umgewandelt werden.
-1 bedeutet, daß Koerper.mat auf NIL
gesetzt wird, 0 bedeutet, daß
Koerper.mat auf das erste aus dem
'MAT '-Chunk gelesene Material gesetzt
wird.
Falls Koerper.art=Flaechen dann
Lese Koerper.panz bis Koerper.kanz (16 Bytes)
Lese Koerperpunkte (12*Koerper.panz Bytes)
Lese Koerperkanten (4*Koerper.kanz Bytes)
Falls Koerper.danz>0 dann
Lese Koerperdreiecke (6*Koerper.danz Bytes)
Falls Koerper.vanz>0 dann
Lese Koerpervierecke (8*Koerper.vanz Bytes)
Falls Koerper.art=Pseudo dann
Falls NOT(pseudoempty IN Weiter) dann
LadeKörper; (nächste Hierarchie-Ebene laden)
Bis NOT(next IN Weiter);
Ende LadeKörper
Falls Chunklänge ungerade : ein Dummybyte lesen
Auszug aus einer Beispielsdatei (Körper 'Verzeichnis' mit Unterkörper
'Scheibe')
4F42 4A310000 02B40200 OBJ1...´..
00000000 00000000 00000000 00000000 ................
00000000 00000080 00004100 00000000 ..........A.....
00000000 00000000 00000080 00004100 ..............A.
00000000 00000000 00000000 00000080 ................
00004100 00000000 00000000 00000000 ..A.............
00000080 00004156 65727A65 6963686E ......AVerzeichn
69730000 00000000 00000000 00000000 is..............
00000080 00004100 00000000 00000000 ......A.........
00000080 00004100 00000000 00000000 ......A.........
00000080 00004180 0000C080 0000C000 ......A...À...À.
00000000 000000FF 020002FF FF040100 ................
00000000 00000000 000000C8 00004700 ...........È..G.
000000C8 00004780 00004100 00000000 ...È..G...A.....
00000000 00000000 000000C8 00004700 ...........È..G.
00000000 00000000 00000000 00000083 ................
126F3600 00000000 00000000 00000000 .o6.............
000000C8 00004753 63686569 62650000 ...È..GScheibe..
00000000 00000000 00000000 00000000 ................
000000C8 00004700 00000000 00000000 ...È..G.........
00000000 000000C8 00004700 00000083 .......È..G.....
126F3600 00000080 0000C080 0000C080 .o6.......À...À.
00004180 000041FF 020002FF FF000000 ..A...A.........
0D000000 0C000000 00000000 18020000 ................
00000000 0000C800 0047C800 00460000 ......È..GÈ..F..
0000AD34 8047AD34 80470000 0000C800 ..4.G4.G....È.
0046C800 00470000 0000DC9B 0011AD34 .FÈ..G....Ü...4
80470000 0000C800 00C6C800 00460000 .G....È..ÆÈ..F..
0000AD34 80C7FF26 C0140000 0000C800 ..4.Ç.&À.....È.
00C7C800 00C60000 0000AD34 80C7AD34 .ÇÈ..Æ....4.Ç4
80C70000 0000C800 00C6C800 00C70000 .Ç....È..ÆÈ..Ç..
0000A574 4093AD34 80C70000 0000C800 ..¥t@.4.Ç....È.
0046C800 00C60000 0000AD34 80470000 .FÈ..Æ....4.G..
00000000 00000000 0000000A 000C0001 ................
0002000A 000B0008 00090009 000C0008 ................
000C0006 00070002 000C0000 000C0003 ................
000C0002 00030001 000C0003 00040000 ................
00010004 000C0007 00080000 000B000B ................
000C0004 00050005 000C0009 000A0006 ................
000C0007 000C0005 00060000 0001000C ................
00010002 000C0002 0003000C 00030004 ................
000C0004 0005000C 00050006 000C0006 ................
0007000C 00070008 000C0008 0009000C ................
0009000A 000C000A 000B000C 000B0000 ................
000C ..
'UMG1'-Chunk
************
Lese Boden.ex (1 Byte)
Lese Himmel.ex (1 Byte)
Lese Materialnummer des Bodens (2 Bytes, siehe 'OBJ1'-Chunk)
Lese Materialnummer des Himmels (2 Bytes, siehe 'OBJ1'-Chunk)
Lese Boden.info (66 Bytes)
Lese Himmel.info (66 Bytes)
Lese Kamera.p1 bis Kamera.zoom (36 Bytes)
Lese Hintergrund.f bis Hintergrund.iffname (94 Bytes)
Auszug aus einer Beispielsdatei
554D 47310000 010C0000 UMG1......
FFFFFFFF 00000000 00000000 00000000 ................
FA000049 00000000 00000000 00000000 ú..I............
00000000 FA000049 00000000 80000041 ....ú..I.......A
00000000 800000C0 800000C0 80000041 .......À...À...A
80000041 FF020000 00000000 00000000 ...A............
0000FA00 00490000 00000000 00000000 ..ú..I..........
0000FA00 00490000 00000000 00000000 ..ú..I..........
0000FA00 00490000 00008000 00C08000 ..ú..I.......À..
00418000 0041FF00 9600004A 9600004A .A...A.....J...J
FA0000CA 00000000 00000000 00000000 ú..Ê............
8C000048 00000000 80000041 CCCCCD3E ...H.......AÌÌÍ>
CCCCCD3E CCCCCD3E 80000041 80000041 ÌÌÍ>ÌÌÍ>...A...A
80000041 C8000047 04000000 00000000 ...AÈ..G........
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 00000000 00000000 ................
00000000 00000000 0000 ..........
'FRE1'-Chunk
************
Lese ansicht (1 Byte)
Lese quadrant (1 Byte)
Lese zoom (4 Bytes)
Lese mittelpunkt (12 Bytes)
Der 'FRE1'-Chunk ist ein sehr langer Chunk mit mehr als 2 KB Daten. Er
enthält sämtliche Requestereinstellungen. Von Interesse dürften aber nur
die ersten 18 Bytes sein. Darin sind Daten über den sichtbaren Ausschnitt
in den 2D-Ansichten enthalten. Wenn Sie solch einen 'FRE1'-Chunk
abspeichern wollen, dann reicht es, diese 18 Bytes zu speichern. Cinema4D
erkennt, daß es sich dabei nicht um die 'Vollversion' des Chunks handelt
und übernimmt nur diese Parameter.
In 'ansicht' steht die sichtbare Ansicht (0=XY, 1=ZY, 2=XZ, 3=3D, 4=4T).
In 'quadrant' steht nochmals der gleiche Wert, es sei denn 4T ist
eingestellt. In diesem Fall muß 'quadrant' auf XY, ZY, XZ oder 3D stehen.
'zoom' ist ein FFP-Wert und gibt den Zoomfaktor an, der sich im Bereich
von 0.001 bis 1000 bewegen darf. 'mittelpunkt' ist ein Vektor, der den
Mittelpunkt des sichtbaren Ausschnitts festlegt.
Auszug aus einer Beispielsdatei
4B494C31 00000012 04003FF0 00000000 FRE1......?ð...
00000000 00000000 0000 ...........
Zur Verdeutlichung des Ganzen folgt eine Routine zum Speichern von Daten:
*************************************************************************
PROCEDURE SpeichereSzene(adr:ADDRESS):BOOLEAN;
PROCEDURE MatNum(mp:MaterialPtr):INTEGER;
VAR
i : INTEGER;
map : MaterialPtr;
BEGIN
IF mp#NIL THEN
i:=0;
map:=welt.nextmat;
WHILE map#mp DO
map:=map^.nextmat;
INC(i);
END;
ELSE
i:=-1;
END;
RETURN i;
END MatNum;
PROCEDURE SpeichereKoerper;
PROCEDURE SaveKoerper(op:KoerperPtr; VAR incb:LONGINT);
VAR
u : WEITER;
ii : INTEGER;
BEGIN
IF op#NIL THEN
Schreibe(ADR(op^.typ),1);
Schreibe(ADR(op^.mp),SIZE(VEKTOR)*2+SIZE(MATRIX)+SIZE(STRING)+
SIZE(TEXINFO)+2);
INC(incb,SIZE(VEKTOR)*2+SIZE(MATRIX)+SIZE(STRING)+
SIZE(TEXINFO)+2+2+1+1);
(* Materialnummer herausfinden *)
ii:=MatNum(op^.mat);
Schreibe(ADR(ii),2);
IF op^.typ=Flaechen THEN
Schreibe(ADR(op^.panz),4*SIZE(LONGINT));
INC(incb,4*SIZE(LONGINT));
END;
u:=WEITER{};
IF op^.next#NIL THEN INCL(u,next); END;
IF (op^.typ=Pseudo) AND (op^.adr=NIL) THEN
INCL(u,pseudoempty);
END;
Schreibe(ADR(u),1);
IF op^.typ=Flaechen THEN
Schreibe(op^.padr,SIZE(VEKTOR)*op^.panz);
Schreibe(op^.kadr,SIZE(CARDINAL)*2*op^.kanz);
INC(incb,SIZE(VEKTOR)*op^.panz+SIZE(CARDINAL)*2*op^.kanz);
IF op^.dadr#NIL THEN
Schreibe(op^.dadr,3*SIZE(CARDINAL)*op^.danz);
INC(incb,3*SIZE(CARDINAL)*op^.danz);
END;
IF op^.vadr#NIL THEN
Schreibe(op^.vadr,4*SIZE(CARDINAL)*op^.vanz);
INC(incb,4*SIZE(CARDINAL)*op^.vanz);
END;
ELSIF op^.typ=Pseudo THEN
op:=op^.adr;
WHILE (op#NIL) AND allok DO
SaveKoerper(op,incb);
op:=op^.next;
END;
END;
END;
END SaveKoerper;
VAR
incb,rb : LONGINT;
ob : KoerperPtr;
byte : SHORTCARD;
BEGIN
Schreibe(ADR('OBJ1'),8);
incb:=0;
ob:=welt.nextkoerper;
WHILE ob#NIL DO
SaveKoerper(ob,incb);
ob:=ob^.next;
END;
rb:=incb;
IF ODD(incb) THEN
byte:=0;
Schreibe(ADR(byte),1);
INC(rb);
END;
SetPos(-rb-4,current);
Schreibe(ADR(incb),4);
SetPos(0,end);
END SpeichereKoerper;
PROCEDURE SpeichereMaterialien;
VAR
bts,rbts : LONGINT;
mp : MaterialPtr;
byte : SHORTCARD;
u : WEITER;
BEGIN
Schreibe(ADR('MAT1'),8);
bts:=0;
mp:=welt.nextmat;
WHILE mp#NIL DO
Schreibe(mp,SIZE(MATERIAL)-4*5);
INC(bts,SIZE(MATERIAL)-4*5+1);
u:=WEITER{};
IF mp^.nextmat#NIL THEN INCL(u,next); END;
Schreibe(ADR(u),1);
mp:=mp^.nextmat;
END;
rbts:=bts;
IF ODD(bts) THEN
byte:=0;
Schreibe(ADR(byte),1);
INC(rbts);
END;
SetPos(-rbts-4,current);
Schreibe(ADR(bts),4);
SetPos(0,end);
END SpeichereMaterialien;
PROCEDURE SpeichereLichter;
VAR
bts,rbts : LONGINT;
lp : LichtPtr;
byte : SHORTCARD;
u : WEITER;
BEGIN
Schreibe(ADR('LAM1'),8);
bts:=0;
lp:=welt.nextlicht;
WHILE lp#NIL DO
Schreibe(lp,SIZE(LICHT)-4);
INC(bts,SIZE(LICHT)-4+1);
u:=WEITER{};
IF lp^.nextlicht#NIL THEN INCL(u,next); END;
Schreibe(ADR(u),1);
lp:=lp^.nextlicht;
END;
rbts:=bts;
IF ODD(bts) THEN
byte:=0;
Schreibe(ADR(byte),1);
INC(rbts);
END;
SetPos(-rbts-4,current);
Schreibe(ADR(bts),4);
SetPos(0,end);
END SpeichereLichter;
PROCEDURE SpeicherePolygone;
VAR
bts,rbts : LONGINT;
size : LONGINT;
pp : PolygonPtr;
byte : SHORTCARD;
u : WEITER;
BEGIN
Schreibe(ADR('POLY'),8);
bts:=0;
pp:=welt.next;
WHILE pp#NIL DO
Schreibe(pp,23); (* Polygon ohne Punkte *)
INC(bts,23+1);
size:=KoeffizientenGroesse(pp);
Schreibe(ADR(pp^.mp),2*SIZE(VEKTOR));
Schreibe(pp^.padr,SIZE(VEKTOR)*pp^.anz);
INC(bts,SIZE(VEKTOR)*pp^.anz+2*SIZE(VEKTOR));
IF size>0 THEN
Schreibe(pp^.koadr,size);
INC(bts,size);
END;
u:=WEITER{};
IF pp^.next#NIL THEN INCL(u,next); END;
Schreibe(ADR(u),1);
pp:=pp^.next;
END;
rbts:=bts;
IF ODD(bts) THEN
byte:=0;
Schreibe(ADR(byte),1);
INC(rbts);
END;
SetPos(-rbts-4,current);
Schreibe(ADR(bts),4);
SetPos(0,end);
END SpeicherePolygone;
PROCEDURE SpeichereUmgebung;
VAR
size : LONGINT;
i : INTEGER;
BEGIN
WITH welt.umgebung DO
Schreibe(ADR('UMG1'),4);
size:=6+2*SIZE(boden.info)+SIZE(xyzkamera)-
3*SIZE(VEKTOR)+SIZE(hintergrund)-4;
Schreibe(ADR(size),4);
Schreibe(ADR(boden.ex),1);
Schreibe(ADR(himmel.ex),1);
i:=MatNum(boden.mat);
Schreibe(ADR(i),2);
i:=MatNum(himmel.mat);
Schreibe(ADR(i),2);
Schreibe(ADR(boden.info),SIZE(boden.info));
Schreibe(ADR(himmel.info),SIZE(himmel.info));
Schreibe(ADR(xyzkamera),SIZE(xyzkamera)-3*SIZE(VEKTOR));
Schreibe(ADR(hintergrund),SIZE(hintergrund)-4);
END;
END SpeichereUmgebung;
VAR
size : LONGINT;
ver : RECORD
version,revision : SHORTCARD;
END;
BEGIN
Schreibe(ADR(FORM),8);
Schreibe(ADR(FRAY),4);
Schreibe(ADR(VERS),4);
size:=2;
Schreibe(ADR(size),4);
ver.version:=VERSION; ver.revision:=REVISION;
Schreibe(ADR(ver),2);
IF welt.nextpolygon#NIL THEN
SpeicherePolygone;
END;
IF welt.nextmat#NIL THEN
SpeichereMaterialien;
END;
SpeichereUmgebung;
IF welt.nextkoerper#NIL THEN
SpeichereKoerper;
END;
IF welt.nextlicht#NIL THEN
SpeichereLichter;
END;
size:=Seek(file,0,end);
DEC(size,8);
SetPos(4,beginning);
Schreibe(ADR(size),4);
END SpeichereSzene;
*******************************************************************************
Programmieren von Erweiterungen :
Jede Erweiterung ist ein selbstständiges Programm. Sind die Erweiterungen
in die entsprechenden Ordner von Cinema 4D gelegt, werden sie automatisch
erkannt und in das Menü aufgenommen. Erweiterungen für die 68881-er Version
müssen die Endung .881 haben, Erweiterungen für die 68000-er Version
sollten keine Endung haben. Bitte beachten Sie, daß wenn Sie eine
Erweiterung für die 68881-er Version von Cinema 4D programmieren,
überall LONGREAL-Werte anstelle von FFP-Werten eingesetzt werden!
Erweiterungen werden von Cinema4D aus aufgestartet. Sie bekommen eine
WBStartup-Message übergeben (siehe AMIGA ROM Kernel Manuals). Nach den
Daten der Startup-Message folgen spezifische Daten, die Cinema4D der
aufgestarteten Erweiterung zur Verfügung stellt. Diese Daten können von
der Erweiterung geändert werden. Bei Programmstart muß abgetestet werden,
daß die übergebene Message genau so groß wie definiert ist, um Abstürze zu
verhindern, falls die Erweiterung von der Workbench oder einem anderen
Programm aufgestartet wird.
Die erweiterte Startup-Message sieht folgendermaßend aus:
TYPE
NEWSTARTUPMSG : RECORD
wb : WBStartup;
sp : ScreenPtr;
wp : WindowPtr;
nextkoerper,aktukoerper,verzeichnis : KoerperPtr;
nextlicht,aktulicht : LichtPtr;
nextpolygon,aktupolygon : PolygonPtr;
nextmat : MaterialPtr;
umgebung : POINTER TO UMGEBUNG;
requester,undo : BOOLEAN;
center : VEKTOR;
redrawaktu,fullrefresh : BOOLEAN;
insertkoerper : KoerperPtr;
verwirbeln : KoerperPtr;
matrizenanpassen : KoerperPtr;
rethinkpolygon : PolygonPtr;
reserved : ARRAY [0..99] OF CHAR;
END;
Alle Werte außer 'sp' und 'wp' dürfen geändert werden.
'sp' ist der ScreenPtr des Cinema-Bildschirms. 'wp' ist der dazugehörige
WindowPtr. 'nextkoerper' ist ein Zeiger auf den ersten Körper auf höchster
Hierarchie-Ebene. 'aktukoerper' ist ein Zeiger auf den aktiven Koerper.
Ist 'aktukoerper'#NIL, dann wird der entsprechende Körper im Editor in
roter Farbe gezeichnet. Sollte ein Körper von einer Erweiterung gelöscht
werden, so muß überprüft werden, ob 'aktukoerper' nicht darauf zeigt und
gegebenenfalls auf NIL gesetzt werden. 'verzeichnis' zeigt auf den Körper,
der 'aktukoerper' hierarchisch übergeordnet ist. Wenn zum Beispiel
'aktukoerper' auf das Objekt 'Finger' gesetzt wurde, muß 'verzeichnis' auf
'Hand' zeigen. Gibt es keinen übergeordneten Körper, dann steht
'verzeichnis' auf NIL. Da Lichtquellen und Polygone linear verkettet sind,
gibt es nur für Körper den Zeiger 'verzeichnis'. 'nextlicht' und
'nextpolygon' sind Zeiger auf die jeweils erste Lichtquelle bzw. das erste
Polygon. Wenn 'aktukoerper'#NIL ist, dann müssen 'aktulicht' und
'aktupolygon' auf NIL stehen und umgekehrt. 'nextmat' ist ein Zeiger auf
das erste Material. 'umgebung' zeigt auf die Umgebungswerte einer Szene.
'requester' gibt an, ob des Menü mit Shift angewählt wurde. Falls eine
Erweiterung irgendwelche Eingabeparameter benötigt, dann sollte das
Cinema4D-Konzept beibehalten werden: Aufruf ohne Shift-->kein Requester,
Aufruf mit Shift-->Requester.
'undo' sollte von der Erweiterung auf TRUE gesetzt werden, wenn eine Aktion
rückgängig machbar ist. Nur dann kann der Benutzer den Menüpunkt
Rückgängig anwählen. Nur Aktionen, die den aktiven Körper, die aktive
Lichtquelle oder das aktive Polygon ändern, lassen sich rückgängig machen.
In 'center' steht der Mittelpunkt der Arbeitsoberfläche. Falls irgendwelche
neuen Objekte erzeugt werden, sollten Sie zentriert auf dem Bildschirm
erscheinen.
Mit 'redrawaktu' und 'fullrefresh' teilen Sie Cinema4D mit, was nach der
Beendigung der Erweiterung passieren soll. Standardmäßig stehen beide Werte
auf FALSE, so daß gar nichts passiert. Wird 'redrawaktu' auf TRUE gesetzt,
dann wird das aktive Objekt neu gezeichnet. Wird 'fullrefresh' auf TRUE
gesetzt, dann wird die Szene komplett neu aufgebaut. Dies ist immer dann
erforderlich, wenn die Erweiterung sich an inaktiven Objekten, der Kamera
o.ä. zu schaffen gemacht hat. Soll die gesamte Szene neu gezeichnet werden,
so reicht es, 'fullrefresh' zu setzen. 'redrawaktu' muß nicht gesetzt
werden.
Neue Körper müssen immer an der richtigen Stelle, in dem Verzeichnis
'verzeichnis' eingehängt werden. Damit Sie als Programmierer nicht so viel
Aufwand haben, können Sie auch einen neu erzeugten Körper in
'insertkoerper' eintragen. Cinema4D hängt den Körper dann selber in die
Listen an die richtige Stelle ein. Gleichzeitig wird der neue Körper
verwirbelt und aktiviert ('redrawaktu' muß also nicht gesetzt werden).
Soll ein Körper verwirbelt werden, dann kann Cinema4D das für Sie
erledigen. Sie müssen dazu nur einen Zeiger auf den Körper in 'verwirbeln'
eintragen. Wenn Ihre Erweiterung die Punkten eines Körpers verändert,
muß die Körpermatrix- und Textur neu angepaßt werden. Dies ist mitunter
eine recht aufwendige Sache. Auch diese Arbeit können Sie Cinema4D
überlassen, wenn Sie den entsprechenden Körper in 'matrizenanpassen'
eintragen. Bei nichtlinearen Polygonen müssen zusätzlich noch einige
Koeffizienten angepaßt werden. Dies kann nur das Hauptprogramm erledigen.
Tragen Sie dazu das Polygon in 'rethinkpolygon' ein.
Es gibt einige Dinge, die Sie keinesfalls tun dürfen:
* Polygone löschen
* Die 'panz' eines nichtlinearen Polygons ändern (wegen der
Koeffizientenberechnung)
* Irgendwelche Speicherbereiche freigeben, ohne den neuen Speicher
erhalten zu haben. Wenn Sie beispielsweise das Punktfeld eines Körpers
vergrößern wollen, müssen Sie zuerst den neuen Speicher alloziieren und
dürfen erst dann den alten in 'padr' angegebenen Speicherbereich freigeben.
Ansonsten kann es passieren, daß nicht genügend Speicher für den neuen
Speicherbereich zur Verfügung steht und der alte schon freigegeben wurde.
* sp oder wp verändern
* Eine Lichtquelle oder einen Körper löschen, ohne 'aktukoerper',
'verzeichnis' und 'aktulicht' überprüft zu haben. Wenn ein Körper
gelöscht wird, müssen natürlich -falls es sich um ein Verzeichnis
handelt- sämtliche Unterkörper überprüft werden.
* Irgendwelche Werte im reserved-Feld ändern